package guggaTests.tasks
{
	import flash.events.Event;
	
	import flexunit.framework.TestCase;
	
	import gugga.eventHelpers.EventDescriptor;
	import gugga.tasks.ExecuteAsyncMethodTask;
	import gugga.tasks.FictiveTask;
	import gugga.tasks.ITask;
	import gugga.tasks.events.TaskEvent;

	public class ExecuteAsyncMethodTaskTest extends TestCase
	{
		private var mTestParameter1:String;
		private var mTestParameter2:Number;
		
		private var delayInterval:Number;
		
		private var mIsTaskStarted : Boolean = false;
		private var mIsInterruptionMethodCalled : Boolean = false;
		
		public function ExecuteAsyncMethodTaskTest(methodName:String=null)
		{
			super(methodName);
		}
		
		public function testCreate() : void
		{	
			var eventSource:FictiveTask = new FictiveTask();
			var eventDescriptor:EventDescriptor = new EventDescriptor(eventSource, TaskEvent.START);
			
			var task:ITask = ExecuteAsyncMethodTask.create(
				eventDescriptor,
				triggerExecuteAsyncMethodCompletionEvent, 
				[eventSource], 
				this);
				
			task.addEventListener(TaskEvent.START, onTaskStarted);
			task.addEventListener(TaskEvent.COMPLETED, addAsync(assertTaskCompleted, 200));
			
			assertNotNull("Task must be not null after creation", task);
			assertNotUndefined("Task must be defined after creation", task);
			
			task.start();
			
			assertTrue("Task should be started and running", mIsTaskStarted);
		}
		
		private function triggerExecuteAsyncMethodCompletionEvent(aEventSource : ITask) : void
		{
			assertNotNull("Arguments must be valid", aEventSource);
			assertNotUndefined("Arguments must be valid", aEventSource);
			
			aEventSource.start();
		}
		
		public function testCreateBasic() : void
		{			
			var eventSource : FictiveTask = new FictiveTask();
			var task : ITask = ExecuteAsyncMethodTask.createBasic(
				TaskEvent.START, 
				triggerCreateBasicTask,
				[eventSource],
				eventSource);
				
			task.addEventListener(TaskEvent.START, onTaskStarted);
			task.addEventListener(TaskEvent.COMPLETED, addAsync(assertTaskCompleted, 200));
			
			assertNotNull("task must be not null after creation", task);
			assertNotUndefined("task must be defined after creation", task);
			
			task.start();
			
			assertTrue("Task should be started and running", mIsTaskStarted);
		}
		
		private function triggerCreateBasicTask(aTriggerCondition:ITask) : void
		{
			assertNotNull("argumets must be valid", aTriggerCondition);
			assertNotUndefined("argumets must be valid", aTriggerCondition);
			
			aTriggerCondition.start();
		}
		
		// This test will assure that the forwarding sequence of the specified 
		// parameters is the same as the parameter sequence in the specified array
		public function testMultipleParametersForwarding() : void
		{
			var eventSource:FictiveTask = new FictiveTask();
			var eventDescriptor:EventDescriptor = new EventDescriptor(eventSource, TaskEvent.START);
			
			mTestParameter1 = new String("value1");
			mTestParameter2 = new Number(13);
			
			var task:ITask = ExecuteAsyncMethodTask.create(
					eventDescriptor,
					this.triggerMultipleParametersTaskCondition,
					[eventSource, mTestParameter1, mTestParameter2],
					this);
					
			task.start();
		}
		
		public function triggerMultipleParametersTaskCondition(
				aTriggerCondition:ITask,
				aTestParameter1:String,
				aTestParameter2:Number) : void
		{
			assertNotNull("argument must not be NULL", aTriggerCondition);
			assertNotUndefined("argument must be defined", aTriggerCondition);
			
			assertNotNull("argument must not be NULL", aTestParameter1);
			assertNotUndefined("argument must be defined", aTestParameter1);
			assertEquals("mTestParamter1 should be equal to aTestParamter1", mTestParameter1, aTestParameter1);
			
			assertNotNull("argument must not be NULL", aTestParameter2);
			assertNotUndefined("argument must be defined", aTestParameter2);
			assertEquals("mTestParamter2 should be equal aTestParamter2", mTestParameter2, aTestParameter2);
			
			aTriggerCondition.start();
		}
		
		public function testIsImmediatelyInterruptable() : void
		{
			var eventSource:FictiveTask = new FictiveTask();
			var eventDescriptor:EventDescriptor = new EventDescriptor(eventSource, TaskEvent.START);
			var task:ITask = ExecuteAsyncMethodTask.create(
				eventDescriptor,
				triggerEmptyFunction,
				[],
				this);
					
			assertTrue(
					"ExecuteAsyncMethodTask.isImmediatelyInterruptable() should be always interrupt immediately", 
					task.isImmediatelyInterruptable());
		}
		
		private function triggerEmptyFunction() : void
		{
			// THIS FUNCTION SHOULD BE EMPTY!!!
		}
		
		/**
		 * OLD: Assure <code>interrupt()</code> will trigger <b><i>interrupted</i></b> 
		 * event instead of <b><i>completed</i></b> event. In other circumstances 
		 * <b><i>interrupted</i></b> event should not be raised.
		 * CURRENT: Assure <code>interrupt()</code> will immediately trigger 
		 * <b><i>interrupted</i></b> event instead of <b><i>completed</i></b> event. 
		 * Event <b><i>completed</i></b> should not be raised at all.
		 */
		 
		 
		public function testInterrupt() : void
		{
			var eventSource:FictiveTask = new FictiveTask();
			var eventDescriptor:EventDescriptor = new EventDescriptor(eventSource, TaskEvent.START);
			var task:ITask = ExecuteAsyncMethodTask.createInteruptable(eventDescriptor, 
				triggerEmptyFunction, 
				[],
				interruptionMethod,
				[],
				this,
				this);
			
			task.addEventListener(TaskEvent.START, onTaskStarted);
			task.addEventListener(TaskEvent.INTERRUPTED, addAsync(assertTaskInterrupted, 300));
			
			task.start();
			
			assertTrue("Task should be started", mIsTaskStarted);
						
			task.interrupt();
			
			assertTrue("", mIsInterruptionMethodCalled);
		}
		
		private function interruptionMethod() : void
		{
			mIsInterruptionMethodCalled = true;
		}
		
		private function assertTaskInterrupted(aEvent : TaskEvent) : void
		{
			var task : ITask = ITask(aEvent.target);
			
			assertFalse("Task should not be running", task.isRunning());
		}
		
		private function assertTaskCompleted(aEvent : TaskEvent) : void
		{
			var task : ITask = ITask(aEvent.target);
			
			assertFalse("Task should be completed not in running state", task.isRunning());
		}

		private function onTaskStarted(aEvent : TaskEvent) : void
		{
			mIsTaskStarted = true;
		}
		
		public override function setUp() : void
		{
			mIsTaskStarted = false;
			mIsInterruptionMethodCalled = false;
		}		
	}
}